package com.bj58.mis.apm.server.statistics.service.impl;

import com.bj58.mis.apm.server.core.util.JsonUtil;
import com.bj58.mis.apm.server.statistics.dto.chart.ValueBean;
import com.bj58.mis.apm.server.statistics.dto.optimize.*;
import com.bj58.mis.apm.server.statistics.dto.rowkey.RowkeyStats;
import com.bj58.mis.apm.server.statistics.mapper.CubeMapper;
import com.bj58.mis.apm.server.statistics.mapper.OptimizeMapper;
import com.bj58.mis.apm.server.statistics.mapper.RowkeyStatsMapper;
import com.bj58.mis.apm.server.statistics.service.BaseService;
import com.bj58.mis.apm.server.statistics.service.OptimizeService;
import com.bj58.mis.apm.server.statistics.service.RowkeyStatsService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: wangxw
 * @Date: 2018/7/2 10:39
 */
@Service
@Transactional
public class OptimizeServiceImpl extends BaseService<OptimizeMapper> implements OptimizeService {

    @Resource
    private RowkeyStatsMapper rowkeyStatsMapper;

    @Override
    public Map<String, String> getLastCube(String cubeId, String userName) {
        if(StringUtils.isNotEmpty(cubeId)) {
            return mapper.getLastCube(cubeId, null);
        }else{
            List<String> cubeids = null;
            if(!super.isAdmin(userName)){
                cubeids = this.getAuthCubeIdList(userName);
                if(cubeids.size() == 0){
                    return new HashMap<>();
                }
            }
            return mapper.getLastCube(null, cubeids);
        }
    }

    /**
     * 查询指定cube的各指标得分
     * @param cubeId
     * @return
     */
    @Override
    public CubeScore getScore(String cubeId) {

        //计算得分，除了模型设计
        List<Map<String, Object>> scores = this.mapper.getScore(cubeId);
        //模型设计得分
        int scoreSum = scores.stream().mapToInt(m -> ((Double)m.get("score")).intValue()).sum();
        Map<String, Object> design = this.mapper.getDesignScore(scoreSum);

        List<NameMax> names = new ArrayList<>();
        List<ValueBean> valueBeans = new ArrayList<>();
        ValueBean vb = new ValueBean();
        valueBeans.add(vb);
        List<Double> value = new ArrayList<>();
        vb.setData(value);
        vb.setName("Cube综合评分");
        vb.setUnit("分");

        NameMax nm = new NameMax();
        nm.setName((String)design.get("name"));
        nm.setMax((Double)design.get("max"));
        value.add((Double)design.get("score"));
        names.add(nm);

        /**
         * 建议列表
         */
        List<String> suggests = new ArrayList<>();
        if(StringUtils.isNotEmpty((String)design.get("suggest"))){
            suggests.add((String)design.get("suggest"));
        }

        for(Map<String, Object> map : scores){
            NameMax nameMax = new NameMax();
            nameMax.setName((String)map.get("name"));
            nameMax.setMax(nm.getMax());
            value.add((Double)map.get("score"));
            names.add(nameMax);
            if(StringUtils.isNotEmpty((String)map.get("suggest"))){
                suggests.add((String)map.get("suggest"));
            }
        }

        valueBeans.forEach( item -> {
            item.setCount(item.getData().size());
            item.setSum(item.getData().stream().mapToDouble(Double::doubleValue).sum());
            if(item.getCount() > 0) {
                item.setAvg(new BigDecimal(item.getSum()).divide(new BigDecimal(item.getCount()), 4, BigDecimal.ROUND_HALF_UP).doubleValue());
            }
        });

        CubeScore cubeScore = new CubeScore();
        cubeScore.setIndicator(names);
        cubeScore.setValueBeans(valueBeans);
        cubeScore.setMax(nm.getMax());
        cubeScore.setMin((Double)design.get("min"));
        cubeScore.setScore(scoreSum + value.get(0));
        cubeScore.setSuggests(suggests);

        return cubeScore;
    }

    /**
     * 查询指定cuboid的数据情况
     * @param cubeId
     * @return
     */
    @Override
    public CuboidStats getShrink(String cubeId) {
        Map<String, Object> statistics = this.mapper.getStatistics(cubeId);
        if(statistics != null){
            String cuboidJson = (String)statistics.get("cuboid_text");
            List<Map<String, Object>> queryCountList = this.mapper.queryCount(cubeId);
            Map<Long , Long> queryCountMap = new HashMap<>();
            queryCountList.forEach(m -> {
                queryCountMap.put((Long)m.get("cuboid"), ((Number)m.get("queryCount")).longValue());
            });
            CuboidStats cs = new CuboidStats();
            Map<String, Object> root = JsonUtil.fromJson(cuboidJson);
            cs.setCount((Long)statistics.get("cuboids"));
            cs.setRoot(buildCuboidShrink(root, null, null, queryCountMap));
            List<RowkeyStats> rowkeys = this.rowkeyStatsMapper.queryRowKeyStats(cubeId);
            cs.setRowkeys(rowkeys.stream().map(rk -> rk.getRowkey()).collect(Collectors.toList()));
            return cs;
        }
        return null;
    }

    /**
     * 构建节点集合
     * @param list
     * @param parent
     * @param root
     * @param queryCountMap
     * @return
     */
    private List<CuboidShrink> buildCuboidShrinkList(List<Map<String, Object>> list, CuboidShrink parent, CuboidShrink root, Map<Long , Long> queryCountMap){
        List<CuboidShrink> subList = new ArrayList<>();
        list.forEach(m -> {
            subList.add(buildCuboidShrink(m, parent, root, queryCountMap));
        });
        subList.sort((CuboidShrink s1, CuboidShrink s2) -> Long.compare(s2.getCuboid(), s1.getCuboid()));
        return subList;
    }

    /**
     * 构建一个节点
     * @param node
     * @param parent
     * @param root
     * @param queryCountMap
     * @return
     */
    private CuboidShrink buildCuboidShrink(Map<String, Object> node, CuboidShrink parent, CuboidShrink root, Map<Long , Long> queryCountMap){
        CuboidShrink cuboid = new CuboidShrink();
        cuboid.setCuboid(getLong(node, "cuboid_id"));
        cuboid.setCuboName(getString(node, "name"));
        cuboid.setRows(getLong(node, "row_count"));
        if(queryCountMap.containsKey(cuboid.getCuboid())) {
            cuboid.setQueryCount(queryCountMap.get(cuboid.getCuboid()));
        }else{
            cuboid.setQueryCount(0L);
        }
        if(parent != null){
            cuboid.setRelativeShrink(calc(cuboid.getRows(), parent.getRows()));
        }
        if(root != null){
            cuboid.setAbsoluteShrink(calc(cuboid.getRows(), root.getRows()));
        }else{
            root = cuboid;
        }
        List<Map<String, Object>> children = (List<Map<String, Object>>)node.get("children");
        if(children != null){
            cuboid.setSubCuboids(buildCuboidShrinkList(children, cuboid, root, queryCountMap));
        }
        return cuboid;
    }

    /**
     * 返回map指定key的Long值
     * @param map
     * @param key
     * @return
     */
    private Long getLong(Map<String, Object> map, String key){
        return ((Double)map.get(key)).longValue();
    }

    /**
     *
     * @param map
     * @param key
     * @return
     */
    private String getString(Map<String, Object> map, String key) {
        return (String)map.get(key);
    }

    private Double calc(Long a, Long b){
        if(b.longValue() == 0L){
            return null;
        }
        return new BigDecimal(a).divide(new BigDecimal(b), 2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

}
